import { BaseCompType } from "/@/components/types";

type BindElement = HTMLElement | SVGElement | Document | Window;

export function on(el: BindElement, event: string, handler: any, capture = false) {
  if (el && event && handler) {
    el.addEventListener(event, handler, capture);
    return handler;
  }
}

export function off(el: BindElement, event: string, handler: any, capture = false) {
  if (el && event && handler) {
    el.removeEventListener(event, handler, capture);
  }
}

type fixHandler = (fix: { offsetX: number; offsetY: number }, e: any) => void;

export function svgElementOn(el: BindElement, event: string, handler: fixHandler, capture = false) {
  if (el && event && handler) {
    const innerHandler = function (e) {
      handler(fixOffsetXY(e), e);
    };
    el.addEventListener(event, innerHandler, capture);
    return innerHandler;
  }
}

/**
 * 在svg的鼠标事件处理过程中，当碰到一些非svg元素（如foreignObject中的HTML元素）时，会导致获取到的offsetX offsetY不是相对于svg的
 * 需要获取其offsetParent进行处理
 * @param e 鼠标事件的event参数
 */
export function fixOffsetXY(e: MouseEvent) {
  let { offsetX, offsetY } = e;
  console.log("fixOffsetXY before========>", offsetX, offsetY);
  let el = e.target as HTMLElement;
  //svg元素没有offsetParent
  let parent: HTMLElement | null;
  if (el.getAttribute("data-type") === BaseCompType.ConfigureIcon) {
    while (el.parentNode && (el.parentNode as HTMLElement).getAttribute("data-type") === BaseCompType.ConfigureIcon) {
      el = el.parentNode as HTMLElement;
    }
    parent = el;
  } else {
    parent = el.offsetParent as HTMLElement;
  }
  while (parent) {
    let x: number, y: number;
    if (parent instanceof SVGElement) {
      x = Number(parent.getAttribute("x")) || 0;
      y = Number(parent.getAttribute("y")) || 0;
    } else {
      x = parent.offsetLeft;
      y = parent.offsetTop;
    }
    offsetX += x;
    offsetY += y;
    if (parent.tagName.toUpperCase() === "FOREIGNOBJECT") {
      const pNode = parent.parentNode as HTMLElement;
      //当平移还没松开鼠标 g下的svg元素的x y还没改变，只改变g的transform的x y值，这时要加上去
      if (pNode && pNode.tagName.toUpperCase() === "G") {
        const dataX = Number(pNode.getAttribute("data-x")) || 0;
        const dataY = Number(pNode.getAttribute("data-y")) || 0;
        if (dataX || dataY) {
          offsetX += dataX;
          offsetY += dataY;
        }
      }
    }
    parent = parent.offsetParent as HTMLElement;
  }
  console.log("fixOffsetXY end========>", offsetX, offsetY);
  return {
    offsetX,
    offsetY,
  };
}

//获取元素的纵坐标
function getTop(el: HTMLElement, pNode?: HTMLElement) {
  let offset = el.offsetTop;
  const offsetParent = el.offsetParent as HTMLElement;
  if (pNode && offsetParent === pNode) return offset;
  if (offsetParent !== null) {
    offset += getTop(offsetParent, pNode);
  }
  return offset;
}
//获取元素的横坐标
function getLeft(el: HTMLElement, pNode?: HTMLElement) {
  let offset = el.offsetLeft;
  const offsetParent = el.offsetParent as HTMLElement;
  if (pNode && offsetParent === pNode) return offset;
  if (offsetParent != null) offset += getLeft(offsetParent, pNode);
  return offset;
}

/**
 * 获取元素相对于某个祖先元素的坐标，若不指定祖先元素则是相对body节点
 * @param el 目标元素
 * @param pNode 祖先元素
 */
export function getElRelativeXY(el: HTMLElement, pNode?: HTMLElement) {
  return {
    x: getLeft(el, pNode),
    y: getTop(el, pNode),
  };
}

export interface RelativeTarget {
  //目标区域
  element: HTMLElement;
  //目标区域相对于body的x坐标
  offsetX: number;
  //目标区域相对于body的y坐标
  offsetY: number;
}

/**
 * 获取目标元素相对对象
 * @param el 目标元素
 * @returns 目标元素相对对象
 */
export function getRelativeTarget(el: HTMLElement): RelativeTarget {
  const point = getElRelativeXY(el);
  return {
    element: el,
    offsetX: point.x,
    offsetY: point.y,
  };
}

/**
 * 获取当前鼠标相对于目标区域的相对坐标
 * @param target element-目标区域, offsetX-目标区域相对于body的x坐标, offsetY-目标区域相对于body的y坐标
 * @param e 当前鼠标事件参数
 */
export function getXYRelativeToTarget({ element, offsetX, offsetY }: RelativeTarget, e: MouseEvent) {
  return {
    offsetX: e.pageX - offsetX + element.scrollLeft,
    offsetY: e.pageY - offsetY + element.scrollTop,
  };
}

export function insterAfter(newEl: Node, targetEl: Node) {
  const parent = targetEl.parentNode;
  if (!parent) return;
  if (parent.lastChild == targetEl) {
    parent.appendChild(newEl);
  } else {
    parent.insertBefore(newEl, targetEl.nextSibling);
  }
}

export function getStyle(el: HTMLElement, attr: string) {
  const style = getComputedStyle(el);
  return style.getPropertyValue(attr);
}
